1 \documentclass[10pt,letterpaper,twocolumn,twosided
]{article
}
2 %\documentclass[10pt,letterpaper]{article}
3 % ---------------------------------------------------------------
4 \usepackage[utf8
]{inputenc}
5 \usepackage[spanish
]{babel
}
7 \usepackage[usenames,dvipsnames
]{color}
13 %Poner la página en landscape
14 \geometry{verbose,landscape,letterpaper,tmargin=
2cm,bmargin=
2cm,lmargin=
2cm,rmargin=
2cm
}
16 \newcommand{\codigofuente}[1]{
20 \setlength{\columnsep}{0.25in
}
21 \setlength{\columnseprule}{1px
}
23 % ---------------------------------------------------------------
25 % ---------------------------------------------------------------
26 \title{Resumen de algoritmos para torneos de programación
}
30 % ---------------------------------------------------------------
32 % ---------------------------------------------------------------
35 \lstloadlanguages{C++
}
36 % ---------------------------------------------------------------
38 \codigofuente{./src/template.cpp
}
39 % ---------------------------------------------------------------
40 \section{Teoría de números
}
41 % ---------------------------------------------------------------
43 %\input{./src/number_theory/bigmod}%.tex
44 \codigofuente{./src/number_theory/bigmod.cpp
}
46 \subsection{Criba de Eratóstenes
}
48 \textbf{Field-testing:
}
50 \item \emph{SPOJ
} -
2912 - Super Primes
51 \item \emph{Live Archive
} -
3639 - Prime Path
55 Marca los números primos en un arreglo. Algunos tiempos de ejecución:
59 SIZE & Tiempo (s) \\
[0.5ex
]
64 100000000 &
7.650 \\
[1ex
]
68 \codigofuente{./src/number_theory/criba.cpp
}
70 \subsection{Divisores de un número
}
71 Imprime todos los divisores de un número (en desorden) en O($
\sqrt{n
}$).
72 Hasta
4294967295 (máximo
\textit{unsigned int
}) responde instantáneamente. Se puede
73 forzar un poco más usando
\textit{unsigned long long
} pero más allá de $
10^
{12}$ empieza a
75 \codigofuente{./src/number_theory/divisores.cpp
}
77 \section{Combinatoria
}
78 \subsection{Cuadro resumen
}
79 Fórmulas para combinaciones y permutaciones:
81 \renewcommand{\arraystretch}{2} %Multiplica la altura de cada fila de la tabla por 2
82 % Si quiero aumentar el tamaño de una fila en particular insertar \rule{0cm}{1cm} en esa fila.
83 \begin{tabular
}{| c | c | c |
}
85 \textit{Tipo
} &
\textit{¿Se permite la repetición?
} &
\textit{Fórmula
} \\
[1.5ex
]
88 $r$-permutaciones & No & $
\displaystyle\frac{n!
}{(n-r)!
} $ \\
[1.5ex
]
90 $r$-combinaciones & No & $
\displaystyle\frac{n!
}{r!(n-r)!
} $ \\
[1.5ex
]
92 $r$-permutaciones & Sí & $
\displaystyle n^
{r
} $ \\
94 $r$-combinaciones & Sí & $
\displaystyle\frac{(n+r-
1)!
}{r!(n-
1)!
} $ \\
[1.5ex
]
97 \renewcommand{\arraystretch}{1}
99 Tomado de
\textit{Matemática discreta y sus aplicaciones
}, Kenneth Rosen,
5$
{}^
{\hbox{ta
}}$ edición, McGraw-Hill, página
315.
101 \subsection{Combinaciones, coeficientes binomiales, triángulo de Pascal
}
102 \emph{Complejidad:
} $ O(n^
2) $ \\
103 $$
{n
\choose k
} =
\left\
{
107 \displaystyle {n -
1 \choose k -
1} +
{n -
1 \choose k
} &
\mbox{en otro caso
}\\
112 \codigofuente{./src/combinatoria/pascal_triangle.cpp
}
115 \textbf{Nota:
} $
\displaystyle {n
\choose k
} $ está indefinido en el código anterior si $ n > k$. ¡La tabla puede estar llena con cualquier basura del compilador!
117 \subsection{Permutaciones con elementos indistinguibles
}
118 El número de permutaciones
\underline{diferentes
} de $n$ objetos, donde hay $n_
{1}$ objetos indistinguibles de tipo
1,
119 $n_
{2}$ objetos indistinguibles de tipo
2, ..., y $n_
{k
}$ objetos indistinguibles de tipo $k$, es
121 \frac{n!
}{n_
{1}!n_
{2}!
\cdots n_
{k
}!
}
123 \textbf{Ejemplo:
} Con las letras de la palabra
\texttt{PROGRAMAR
} se pueden formar $
\displaystyle \frac{9!
}{2!
\cdot 3!
} =
124 30240 $ permutaciones
\underline{diferentes
}.
125 \subsection{Desordenes, desarreglos o permutaciones completas
}
127 Un desarreglo es una permutación donde ningún elemento $i$ está en la
128 posición $i$-ésima. Por ejemplo,
\textit{4213} es un desarreglo de
4 elementos pero
129 \textit{3241} no lo es porque el
2 aparece en la posición
2.
131 Sea $D_
{n
}$ el número de desarreglos de $n$ elementos, entonces:
136 (n-
1)(D_
{n-
1} + D_
{n-
2}) & n
\geq 2\\
140 Usando el principio de inclusión-exclusión, también se puede encontrar la fórmula
142 D_
{n
} = n!
\left [ 1 -
\frac{1}{1!
} +
\frac{1}{2!
} -
\frac{1}{3!
} +
\cdots + (-
1)^
{n
}\frac{1}{n!
} \right ]
143 = n!
\sum_{i=
0}^
{n
} \frac{(-
1)^
{i
}}{i!
}
147 \subsection{Algoritmo de Dijkstra
}
148 El peso de todas las aristas debe ser no negativo.
150 \codigofuente{./src/grafos/dijkstra.cpp
}
152 \subsection{Minimum spanning tree: Algoritmo de Prim
}
154 \codigofuente{./src/grafos/prim.cpp
}
156 \subsection{Minimum spanning tree: Algoritmo de Kruskal + Union-Find
}
157 \codigofuente{./src/grafos/kruskal.cpp
}
159 \subsection{Algoritmo de Floyd-Warshall
}
160 \codigofuente{./src/grafos/floyd.cpp
}
162 \subsection{Algoritmo de Bellman-Ford
}
163 Si no hay ciclos de coste negativo, encuentra la distancia más corta
164 entre un nodo y todos los demás. Si sí hay, permite saberlo. \\ El
165 coste de las aristas
\underline{sí
} puede ser negativo
166 (
\emph{Debería
}, si no es así se puede usar Dijsktra o Floyd).
167 \codigofuente{./src/grafos/bellman.cpp
}
169 \subsection{Puntos de articulación
}
170 \codigofuente{./src/grafos/puntos_articulacion.cpp
}
172 \subsection{Máximo flujo: Método de Ford-Fulkerson, algoritmo de Edmonds-Karp
}
173 El algoritmo de Edmonds-Karp es una modificación al método de Ford-Fulkerson. Este último
174 utiliza DFS para hallar un camino de aumentación, pero la sugerencia de Edmonds-Karp
175 es utilizar BFS que lo hace más eficiente en algunos grafos.
178 \codigofuente{./src/grafos/ford_fulkerson.cpp
}
180 \subsection{Máximo flujo para grafos dispersos usando Ford-Fulkerson
}
181 \codigofuente{./src/grafos/ford_fulkerson_sparse.cpp
}
183 \subsection{Máximo flujo para grafos disperos usando algoritmo de Dinic
}
184 \codigofuente{./src/grafos/dinic.cpp
}
186 \subsection{Máximo flujo mínimo costo
}
187 Implementación de Misof:
188 \codigofuente{./src/grafos/mincostmaxflow.cpp
}
190 \subsection{Componentes fuertemente conexas: Algoritmo de Tarjan
}
192 \codigofuente{./src/grafos/tarjan.cpp
}
194 \subsection{2-Satisfiability
}
195 Dada una ecuación lógica de conjunciones de disyunciones de
2 términos, se pretente decidir si existen valores de verdad que puedan asignarse a las variables para hacer cierta la ecuación. \\
196 Por ejemplo, $(b_1
\vee \neg b_2)
\wedge (b_2
\vee b_3)
\wedge (
\neg b_1
\vee \neg b_2) $ es verdadero cuando $b_1$ y $b_3$ son verdaderos y $b_2$ es falso. \\
197 \textbf{Solución:
} Se sabe que $(p
\rightarrow q)
\leftrightarrow (
\neg p
\vee q)$. Entonces se traduce cada disyunción en una implicación y se crea un grafo donde los nodos son cada variable y su negación. Cada implicación es una arista en este grafo. Existe solución si nunca se cumple que una variable y su negación están en la misma componenete fuertemente conexa (Se usa el algoritmo de Tarjan,
\ref{tarjan
}).
199 \section{Programación dinámica
}
200 \subsection{Longest common subsequence
}
201 \codigofuente{./src/dp/lcs.cpp
}
202 \subsection{Partición de troncos
}
203 Este problema es similar al problema de
\textit{Matrix Chain Multiplication
}. Se tiene
204 un tronco de longitud $n$, y $m$ puntos de corte en el tronco. Se puede hacer un corte a la vez,
205 cuyo costo es igual a la longitud del tronco. ¿Cuál es el mínimo costo para partir todo el tronco
206 en pedacitos individuales?
209 \textbf{Ejemplo:
} Se tiene un tronco de longitud
10. Los puntos de corte son
2,
4, y
7. El mínimo
210 costo para partirlo es
20, y se obtiene así:
212 \item Partir el tronco (
0,
10) por
4. Vale
10 y quedan los troncos (
0,
4) y (
4,
10).
213 \item Partir el tronco (
0,
4) por
2. Vale
4 y quedan los troncos (
0,
2), (
2,
4) y (
4,
10).
214 \item No hay que partir el tronco (
0,
2).
215 \item No hay que partir el tronco (
2,
4).
216 \item Partir el tronco (
4,
10) por
7. Vale
6 y quedan los troncos (
4,
7) y (
7,
10).
217 \item No hay que partir el tronco (
4,
7).
218 \item No hay que partir el tronco (
7,
10).
219 \item El costo total es $
10+
4+
6 =
20$.
223 El algoritmo es $O(n^
3)$, pero optimizable a $O(n^
2)$ con una tabla adicional:
224 \codigofuente{./src/dp/particion_troncos.cpp
}
227 \subsection{Área de un polígono
}
228 Si P es un polígono simple (no se intersecta a sí mismo) su área está dada por: \\
230 $ A(P) =
\frac{1}{2} \displaystyle\sum_{i=
0}^
{n-
1} (x_
{i
} \cdot y_
{i+
1} - x_
{i+
1} \cdot y_
{i
}) $ \\
232 \codigofuente{./src/geometria/polygon_area.cpp
}
234 \subsection{Centro de masa de un polígono
}
235 Si P es un polígono simple (no se intersecta a sí mismo) su centro de masa está dado por: \\
237 $
\displaystyle\bar{C
}_
{x
} =
\frac{ \displaystyle\iint_{R
} x \, dA
}{M
} =
\frac{1}{6M
}\sum_{i=
1}^
{n
} (y_
{i+
1} - y_
{i
}) (x_
{i+
1}^
2 + x_
{i+
1} \cdot x_
{i
} + x_
{i
}^
2) $
241 $
\displaystyle\bar{C
}_
{y
} =
\frac{ \displaystyle\iint_{R
} y \, dA
}{M
} =
\frac{1}{6M
} \sum_{i=
1}^
{n
} (x_
{i
} - x_
{i+
1}) (y_
{i+
1}^
2 + y_
{i+
1} \cdot y_
{i
} + y_
{i
}^
2)$
245 Donde $ M $ es el área del polígono. \\
247 Otra posible fórmula equivalente:
249 $
\displaystyle\bar{C
}_
{x
} =
\frac{1}{6A
} \sum_{i=
0}^
{n-
1} (x_
{i
} + x_
{i+
1}) (x_
{i
} \cdot y_
{i+
1} - x_
{i+
1} \cdot y_
{i
}) $
253 $
\displaystyle\bar{C
}_
{y
} =
\frac{1}{6A
} \sum_{i=
0}^
{n-
1} (y_
{i
} + y_
{i+
1}) (x_
{i
} \cdot y_
{i+
1} - x_
{i+
1} \cdot y_
{i
}) $
256 \subsection{Convex hull: Graham Scan
}
257 \emph{Complejidad:
} $ O(n
\log_{2}{n
}) $
258 \codigofuente{./src/geometria/grahamscan.cpp
}
260 \subsection{Convex hull: Andrew's monotone chain
}
261 \emph{Complejidad:
} $ O(n
\log_{2}{n
}) $
262 \codigofuente{./src/geometria/monotonechain.cpp
}
264 \subsection{Mínima distancia entre un punto y un segmento
}
265 \codigofuente{./src/geometria/distance_point_to_segment.cpp
}
267 \subsection{Mínima distancia entre un punto y una recta
}
268 \codigofuente{./src/geometria/distance_point_to_line.cpp
}
270 \subsection{Determinar si un polígono es convexo
}
271 \codigofuente{./src/geometria/is_convex_polygon.cpp
}
273 \subsection{Determinar si un punto está dentro de un polígono convexo
}
274 \codigofuente{./src/geometria/is_inside_convex_polygon.cpp
}
276 \subsection{Determinar si un punto está dentro de un polígono cualquiera
}
278 \textbf{Field-testing:
}
280 \item \emph{TopCoder
} - SRM
187 - Division
2 Hard - PointInPolygon
282 \codigofuente{./src/geometria/is_inside_concave_polygon.cpp
}
284 \subsection{Intersección de dos rectas
}
285 \codigofuente{./src/geometria/line_line_intersection.cpp
}
287 \subsection{Intersección de dos segmentos de recta
}
288 \codigofuente{./src/geometria/segment_segment_intersection.cpp
}
289 % ---------------------------------------------------------------
290 \section{Estructuras de datos
}
291 \subsection{Árboles de Fenwick ó Binary indexed trees
}
293 Se tiene un arreglo $\
{a_0, a_1,
\cdots, a_
{n-
1}\
}$. Los árboles
294 de Fenwick permiten encontrar $
\displaystyle \sum_{k=i
}^
{j
} a_k $ en orden $O(
\log_{2}{n
})$ para parejas de $(i, j)$ con $i
\leq j$. De la misma manera, permiten sumarle una cantidad a un $a_i$ también en tiempo $O(log_
{2}{n
})$.
296 \codigofuente{./src/estructuras/fenwick.cpp
}
298 \subsection{Segment tree
}
299 \codigofuente{./src/estructuras/segment_tree.cpp
}
301 % ---------------------------------------------------------------
303 \subsection{El
\textit{parser
} más rápido del mundo
}
305 \item Cada no-terminal: un método
306 \item Cada lado derecho:
308 \item invocar los métodos de los no-terminales o
309 \item Cada terminal: invocar proceso
\textit{match
}
311 \item Alternativas en una producción: se hace un
\textit{if
}
314 No funciona con gramáticas recursivas por izquierda ó en las que en algún momento haya
315 varias posibles escogencias que empiezan por el mismo caracter (En ambos casos la gramática se puede factorizar).
318 \textbf{Ejemplo:
} Para la gramática:
320 A
\longrightarrow (A)A
322 A
\longrightarrow \epsilon
325 \codigofuente{./src/misc/parser_recursivo_desc.cpp
}
327 \subsection{Checklist para corregir un Wrong Answer
}
328 Consideraciones que podrían ser causa de un Wrong Answer:
335 El programa termina anticipadamente por la condición en el ciclo de lectura.
336 Por ejemplo, se tiene
\verb_while (cin >> n >> k && n && k)_ y un caso válido de entrada
341 El grafo no es conexo.
345 Puede haber varias aristas entre el mismo par de nodos.
349 Las aristas pueden tener costos negativos.
353 El grafo tiene un sólo nodo.
357 La cadena puede ser vacía.
361 Las líneas pueden tener espacios en blanco al principio o al final (Cuidado al usar
\texttt{getline
} o
\texttt{fgets
}).
365 El arreglo no se limpia entre caso y caso.
369 Estás imprimiendo una línea en blanco con un espacio (
\verb_printf("
\n")_ en vez de
\verb_printf("
\n")_ ó
\verb_puts(" ")_ en vez de
\verb_puts("")_).
373 La rana se puede quedar quieta.
381 \subsection{Entrada desde entrada estándar
}
382 Este primer método es muy fácil pero es mucho más ineficiente porque utiliza Scanner en vez de BufferedReader:
383 \codigofuente{./src/java/io_estandar_easy.java
}
387 Este segundo es más rápido:
388 \codigofuente{./src/java/io_estandar.java
}
389 \subsection{Entrada desde archivo
}
390 \codigofuente{./src/java/io_file.java
}
392 \subsection{Mapas y sets
}
394 \codigofuente{./src/java/maps_sets.java
} \\
395 La salida de este programa es: \\
398 \fbox{\parbox{2.0in
}{
413 \\
\normalfont\normalsize
416 Si quiere usarse una clase propia como llave del mapa o como elemento del set, la clase debe implementar
417 algunos métodos especiales: Si va a usarse un TreeMap ó TreeSet hay que implementar los métodos
\texttt{compareTo
} y
418 \texttt{equals
} de la interfaz
\texttt{Comparable
} como en la sección
\ref{colas_de_prioridad_java
}. Si va a usarse
419 un HashMap ó HashSet hay más complicaciones.\\
421 \textbf{Sugerencia:
} Inventar una manera de codificar y decodificar la clase en una String o un Integer y meter esa representación en el mapa o set: esas clases ya tienen los métodos implementados.
423 \subsection{Colas de prioridad
}
424 \label{colas_de_prioridad_java
}
425 Hay que implementar unos métodos. Veamos un ejemplo: \\
426 \codigofuente{./src/java/priority_queue.java
}\\
427 La salida de este programa es: \\
430 \fbox{\parbox{2.0in
}{
431 peso =
0, destino =
12\\
432 peso =
0, destino =
8\\
433 peso =
0, destino =
13\\
434 peso =
3, destino =
7\\
435 peso =
1876, destino =
4\\
438 \normalfont\normalsize
440 Vemos que la función de comparación que definimos no tiene en cuenta
\texttt{destino
},
441 por eso no desempata cuando dos
\texttt{Items
} tienen el mismo
\texttt{peso
} si no que escoge
442 cualquiera de manera arbitraria.
445 \subsection{Entrada desde archivo
}
446 \codigofuente{./src/c++/io_file.cpp
}
448 \subsection{Strings con caractéres especiales
}
449 \codigofuente{./src/c++/unicode.cpp
}
451 \emph{Nota
}: Como alternativa a la función getline, se pueden utilizar las funciones fgetws y fputws, y más adelante swscanf y wprintf:
452 \codigofuente{./src/c++/fgetws.cpp
}